package com.icee.myth.common;

import com.icee.myth.common.channelContext.HeartbeatChannelContext;
import com.icee.myth.common.message.serverMessage.Message;
import com.icee.myth.utils.LogConsts;
import com.icee.myth.utils.MLogger;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;

import java.net.InetSocketAddress;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.LinkedTransferQueue;

import static com.icee.myth.utils.Consts.RECONNECT_PERIOD;

//import com.icee.myth.common.messageQueue.ServerMessageQueue;
//import com.icee.myth.deamon.channelHandler.DeamonToManagerHandler;
//import com.icee.myth.manager.channelHandler.ManagerToClusterHandler;

/**
 * @author liuxianke
 */
public abstract class AbstractHeartbeatClient implements Client {

    protected String host; // Server的主机地址
    protected int port; // Server的端口地址
    protected Bootstrap bootstrap;
    protected final HeartbeatChannelContext channelContext; // channelContext connect to server
    private Timer connectTimer; //断线重连定时器

    protected LinkedTransferQueue<Message> queue;

    public AbstractHeartbeatClient() {
        channelContext = new HeartbeatChannelContext();
    }

    abstract public void init(String host, int port, final boolean deamonToManager, final int managerToClusterServerId, final LinkedTransferQueue<Message> queue);
//       {
//        this.queue = queue;
//        this.host = host;
//        this.port = port;
//
//        this.bootstrap = new Bootstrap();
//        bootstrap.group(new NioEventLoopGroup());
//        bootstrap.channel(NioSocketChannel.class);
//        bootstrap.remoteAddress(new InetSocketAddress(host, port));
//        bootstrap.option(ChannelOption.TCP_NODELAY, true);
//        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
//        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
//            @Override
//            public void initChannel(SocketChannel ch)
//                    throws Exception {
//                ch.pipeline().addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 2, 4, 0, 0));
//
//                if (deamonToManager) {
//                    // deamonToManager
//                    ch.pipeline().addLast("deamonToManagerEncoder", new Type2BytesLengthFieldProtobufEncoder());   //customEncoder
//                    ch.pipeline().addLast("deamonToManagerHandler", new DeamonToManagerHandler());
//                } else {
//                    // managerToGameServerCluster
//                    ch.pipeline().addLast("customPbEncoder", new Type2BytesLengthFieldProtobufEncoder());
//                    ch.pipeline().addLast("managerToClusterHandler", new ManagerToClusterHandler(managerToClusterServerId));
//                }
//            }
//        });
//        System.out.printf("ip=%s,port=%d,HeartbeatClient init ok\n", host, port);
//    }

    @Override
    public void connectToServer() {
        // 连接服务
        // Start the connection attempt.
        MLogger.getlogger().debuglog(LogConsts.LOGLEVEL_INFO, "Connecting to server...host=" + host + ",port=" + port);
        ChannelFuture f = bootstrap.connect(new InetSocketAddress(host, port));
        if (null != f) {
            f.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                        System.out.printf("HeartbeatClient connect ip=%s,port=%d ok\n", host, port);
                    } else {
                        future.cause().printStackTrace();
                    }
                }
            });
        }
    }

    @Override
    public HeartbeatChannelContext getChannelContext() {
        return channelContext;
    }

    public void flush() {
        channelContext.flush();
    }

    protected void heartbeat() {
        // 向对方发送心跳消息
        channelContext.write(buildClientHeartBeat());

        // 心跳计数减一
        int beatNum = channelContext.heartbeat();
        // 心跳计数小于等于0表示发生故障
        if (beatNum <= 0) {
            // 当心跳计数为0时，向消息队列中产生一服务故障消息。
            if (beatNum == 0) {
//                ServerMessageQueue.queue().offer(buildServerDownMessage());
                this.queue.offer(buildServerDownMessage());

                channelContext.close();
            }
            // TODO: 报警，当心跳计数小于等于0后产生连续的报警
            serverDownWarning();
        }
    }

    protected void restoreHeartbeat() {
        channelContext.restoreHeartbeat();
    }

    protected void serverConnect(Channel channel) {
        channelContext.setChannel(channel);
        channelContext.restoreHeartbeat();
    }

    protected void serverClose() {
        channelContext.close();
        serverCloseWarning();
    }

    protected void reconnect() {
        // 重新连接cluster server
        connectTimer = new Timer();
        connectTimer.schedule(
                new TimerTask() {

                    @Override
                    public void run() {
                        connectToServer();
                        connectTimer.cancel();
                    }
                }, RECONNECT_PERIOD);
    }

    protected abstract Object buildClientHeartBeat();

    protected abstract Message buildServerDownMessage();

    protected abstract void serverDownWarning();

    protected abstract void serverCloseWarning();
}
